package com.cskaoyan.javase.recursion._0introduction;

/**
 * 递归的引入
 * 递归的定义
 * 我们已经学习过方法，使用过方法了。
 * 方法体中是可以调用方法的，那么如果在方法体中调用方法自身呢？
 *
 * 特别的，在一个方法当中再次调用这个方法
 * 就像故事里提到同样的故事一样
 * 我们把方法在运行时调用自身的情况，称之为递归，又叫做递归调用。
 *
 * 递归的使用:
 *      1.要想使用递归,那么在方法体中必须存在调用自身方法的语句
 *          方法中调用自身方法的语句,称之为"递归体"
 *          递归体对于递归而言是必不可少的
 *
 *      2.要想递归正常运行,递归还需要一个终止的条件,称之为"递归的出口"
 *          一个合法的递归,必须要有递归的出口
 *
 *      3.递归体和递归的出口是递归使用的二要素,缺一不可
 *      思考:
 *      一个具有出口的递归,就一定能够正常运行吗?
 *      不一定
 *      如果递归的出口过于遥远
 *      导致递归的次数(递归的深度)仍然超过了栈内存的大小,那么仍然会栈溢出
 *      所以使用递归还需要考虑递归的深度
 *
 * 综上所述,使用递归是一个很危险的事情
 * 递归必须要有出口,即便有出口,也不一定是安全
 * 在实际开发中,不要随便就想着用递归,只有确实没有其它解决方案或者其它解决方案过于麻烦时,才去考虑使用递归.
 *
 *
 * @since 10:56
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*
            分析:
            sum(10) = 10 + sum(9);
            sum(9) = 9 + sum(8);
            sum(8) = 8 + sum(7);
            ....
            这个程序的结果应该是什么呢?
                1.死循环
                2.程序报错
                3.电脑炸了

           显然以上方法调用的过程是无法自行停止的
           会不断的存在方法调用,不断的存在方法进栈,但是方法始终没有调用结束,始终没有方法出栈
           于是终于,JVM栈内存空间有限,方法只进栈不出栈,就会导致栈内存不够用,导致"栈溢出"
           于是程序只好抛出一个异常"StackOverflowError"(JVM栈溢出错误)
           然后终止程序执行
         */
        System.out.println(sum(1000));
    }

    public static int sum(int num) {
        // 递归的出口
        if (num == 0) {
            return 0;
        }
        // 递归体
        return num + sum(num - 1);
    }
}
